﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;

namespace cangfengUI
{
    //******************************************************************************
    //
    //     说明：图形按钮类
    //     原作者：Vartan Simonian 
    //     链接：http://www.codeproject.com/Articles/29010/WinForm-ImageButton
    //     
    //******************************************************************************

    //继承这个接口IButtonControl，允许这个控件用作窗体上的按钮
    public class ImageButton : PictureBox, IButtonControl
    {
        private DialogResult _DialogResult;
        private Image _HoverImage;
        private Image _DownImage;
        private Image _NormalImage;

        private bool _hover = false;
        private bool _down = false;
        private bool _isDefault = false;
        private bool _holdingSpace = false;

        private const int WM_KEYDOWN = 0x0100;
        private const int WM_KEYUP = 0x0101;

        private ToolTip _toolTip = new ToolTip();

        //构造函数,继承于picturbox的构造函数
        public ImageButton()
            : base()
        {
            //背景设置为透明
            this.BackColor = Color.Transparent;

            //默认按钮大小
            this.Size = new Size(75, 23);
        }

        #region IButtonControl接口的实现
        /// <summary>
        /// IButtonControl接口的实现
        /// </summary>

        public DialogResult DialogResult
        {
            get
            {
                return _DialogResult;
            }
            set
            {
                if (Enum.IsDefined(typeof(DialogResult), value))
                {
                    _DialogResult = value;
                }
            }
        }

        public void NotifyDefault(bool value)
        {
            if (_isDefault != value)
            {
                _isDefault = value;
            }
        }

        public void PerformClick()
        {
            base.OnClick(EventArgs.Empty);
        } 
        #endregion

        //按钮属性
        [Category("Appearance")]
        [Description("鼠标移动到控件显示的图片")]
        public Image HoverImage
        {
            get { return _HoverImage; }
            set { _HoverImage = value; if (_hover) Image = value; }
        }

        [Category("Appearance")]
        [Description("鼠标按住控件显示的图片")]
        public Image DownImage
        {
            get { return _DownImage; }
            set { _DownImage = value; if (_down) Image = value; }
        }

        [Category("Appearance")]
        [Description("控件平常情况显示的图片")]
        public Image NormalImage
        {
            get { return _NormalImage; }
            set { _NormalImage = value; if (!(_hover || _down)) Image = value; }
        }

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        [Description("显示的文本")]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
            }
        }

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        [Description("显示文本的字体")]
        public override Font Font
        {
            get
            {
                return base.Font;
            }
            set
            {
                base.Font = value;
            }
        }
        [Description("当鼠标移动到此控件处显示的文本")]
        public string ToolTipText { get; set; }

        #region 属性描述变化
        [Description("控制ImageButton如何处理图像的位置和控制大小")]
        public new PictureBoxSizeMode SizeMode { get { return base.SizeMode; } set { base.SizeMode = value; } }

        [Description("控制ImageButton应该有什么类型的边框")]
        public new BorderStyle BorderStyle { get { return base.BorderStyle; } set { base.BorderStyle = value; } }
        #endregion

        #region 隐藏的属性

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image Image { get { return base.Image; } set { base.Image = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image BackgroundImage { get { return base.BackgroundImage; } set { base.BackgroundImage = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new String ImageLocation { get { return base.ImageLocation; } set { base.ImageLocation = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image ErrorImage { get { return base.ErrorImage; } set { base.ErrorImage = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image InitialImage { get { return base.InitialImage; } set { base.InitialImage = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool WaitOnLoad { get { return base.WaitOnLoad; } set { base.WaitOnLoad = value; } }
        #endregion

        //重载控件的方法
        #region  重载控件的方法
        protected override void OnMouseEnter(EventArgs e)
        {
            //显示浮动文字
            if (ToolTipText != string.Empty)
            {
                HideToolTip();
                ShowTooTip(ToolTipText);
            }
            base.OnMouseEnter(e);
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            //设置移动到控件的属性为true
            _hover = true;
            //如果按下了控件
            if (_down)
            {
                //如果不是显示的按下控件的图片
                if (_DownImage != null && Image != _DownImage)
                {
                    //图片显示按下控件的图片
                    Image = _DownImage;
                }
            }
            //如果没按下控件
            else
            {
                //如果移动到控件显示的不是空
                if (_HoverImage != null)
                    Image = _HoverImage;
                else
                    Image = _NormalImage;
            }
            //最后基类的方法
            base.OnMouseMove(e);
        }
        //鼠标离开控件
        protected override void OnMouseLeave(EventArgs e)
        {
            //显示回正常图片
            _hover = false;
            Image = _NormalImage;
            base.OnMouseLeave(e);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            //控件聚焦
            base.Focus();
            OnMouseUp(null);
            _down = true;
            if(_DownImage!=null)
            Image = _DownImage;
            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            _down = false;
            if (_hover)
            {
                if (_HoverImage != null)
                {
                    Image = _HoverImage;
                }
                else
                {
                    Image = NormalImage;
                }
            }
            base.OnMouseUp(e);
        }

        protected override void OnLostFocus(EventArgs e)
        {
            _holdingSpace = false;
            OnMouseUp(null);
            base.OnLostFocus(e);
        }

        //在调度键盘或输入消息之前，在消息循环内对它们进行预处理。
        /*
        Simply put, we trap the message sent to the control if it is a key up or key down event. If it is, we check what key it is. 
        If it's the enter key, we simply invoke a click event. If it's the spacebar, we hold the button down while it's being pressed until:
            1、 the user lets go of the spacebar, in which case we perform a click, or 
            2、the user presses Escape, Tab, or the control loses focus, in which case we do not invoke the click event
        If it is not the spacebar and it is not the enter key, we let the PictureBox base class method handle the message.
         */
        public override bool PreProcessMessage(ref Message msg)
        {
            if (msg.Msg == WM_KEYUP)
            {
                if (_holdingSpace)
                {
                    if ((int)msg.WParam == (int)Keys.Space)
                    {
                        OnMouseUp(null);
                        PerformClick();
                    }
                    else if ((int)msg.WParam == (int)Keys.Escape
                        || (int)msg.WParam == (int)Keys.Tab)
                    {
                        _holdingSpace = false;
                        OnMouseUp(null);
                    }
                }
                return true;
            }
            else if (msg.Msg == WM_KEYDOWN)
            {
                if ((int)msg.WParam == (int)Keys.Space)
                {
                    _holdingSpace = true;
                    OnMouseDown(null);
                }
                else if ((int)msg.WParam == (int)Keys.Enter)
                {
                    PerformClick();
                }
                return true;
            }
            else
                return base.PreProcessMessage(ref msg);
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            if (!string.IsNullOrEmpty(Text) && pe != null && (base.Font != null))
            {
                //测量对应字体和文字的尺寸
                SizeF drawStringSize = pe.Graphics.MeasureString(base.Text,base.Font);

                //文字显示的位置
                //垂直和水平居中
                PointF drawPoint;
                if (base.Image != null)
                {
                    drawPoint = new PointF(
                        base.Image.Width / 2 - drawStringSize.Width / 2,
                        base.Image.Height / 2 - drawStringSize.Height / 2);
                }
                else
                {
                    drawPoint = new PointF(
                        base.Width / 2 - drawStringSize.Width / 2,
                        base.Height / 2 - drawStringSize.Height / 2);
                }
                //定义一个画笔
                using (SolidBrush drawBrush = new SolidBrush(base.ForeColor))
                {
                    //把文字画上去
                    pe.Graphics.DrawString(base.Text, base.Font, drawBrush, drawPoint);
                }
            }
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_toolTip != null)
                    _toolTip.Dispose();
            }
            _toolTip = null;
            base.Dispose(disposing);
        }

        protected override void OnTextChanged(EventArgs e)
        {
            Refresh();
            base.OnTextChanged(e);
        }

        #endregion

        #region Private

        private void ShowTooTip(string toolTipText)
        {
            _toolTip.Active = true;
            _toolTip.SetToolTip(this, toolTipText);
        }

        private void HideToolTip()
        {
            _toolTip.Active = false;
        }

        #endregion
    }

}
